package cn.initcap.designpattern.pattern.creational.singleton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 单例模式
 *
 * @author initcap
 * @date 2018/8/28 AM9:09
 */
public class Test {

    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

//        // 序列化破坏单例模式
//        destroySerializableSingleton();
//        // 反射破坏单例模式
//        destroyReflectSingleton();
//        // 保证线程安全的单例模式测试
//        singletonTest();

        singletonClassMathend();

    }

    private static void singletonTest() {
        // 【synchronized】锁整个类，性能低
        singletonThreadRun(Runner.LAZYSINGLETON);
        // 【DCL】防止指令重排序的方式
        singletonThreadRun(Runner.LAZYDOUBLECHECKSINGLETON);
        // 【静态内部类】JVM有Class对象的初始化锁，在初始化时其他线程无法访问，所以即使指令重排序也没有关系
        singletonThreadRun(Runner.STATICINNERCLASSSINGLETON);
        singletonThreadRun(Runner.CONTAINERSINGLETON);
        // 线程级别的类
        singletonThreadRun(Runner.THREADLOCALINSTANCE);
        // 这个是单例模式最佳实践，可以防止序列化攻击和反射攻击
        singletonThreadRun(0);
    }

    /**
     * 序列化破坏单例模式
     */
    private static void destroySerializableSingleton() throws IOException, ClassNotFoundException {

        HungrySingleton instance = HungrySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(instance);
        File file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        HungrySingleton newInstance = (HungrySingleton) ois.readObject();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);
    }

    /**
     * 反射破坏单例模式
     *
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    private static void destroyReflectSingleton() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        // 可以替换成【StaticInnerClassSingleton.class/LazySingleton.class/EnumInstance.class】
        Class objectClass = HungrySingleton.class;

        Constructor constructor = objectClass.getDeclaredConstructor();
        // 将private修饰符改为可以调用；
        constructor.setAccessible(true);

        HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
        HungrySingleton instance = HungrySingleton.getInstance();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance == newInstance);

    }

    /**
     * 使用两个线程检验单例模式的安全性
     * 多线程debug
     *
     * @param type @see Runner.class
     */
    private static void singletonThreadRun(int type) {
        Thread t1 = new Thread(new Runner(type));
        Thread t2 = new Thread(new Runner(type));
        t1.start();
        t2.start();
        System.out.println("program end");
    }

    private static void singletonClassMathend() {
        Thread t1 = new Thread(new MapRunner());
        Thread t2 = new Thread(new MapRunner());
        t1.start();
        t2.start();
        System.out.println("program end");
    }
}
